//
//  camera.cpp
//  RenderV1
//
//  Created by 黄翔 on 2019/8/25.
//  Copyright © 2019 黄翔. All rights reserved.
//
#include "Camera.h"
#include "Input.h"
#include "Time.h"
#include "render_v1.h"
#include <algorithm>

using namespace hxe;

Camera::Camera(Vector3 forward, Vector3 up, float fov, float aspect, float near, float far): Component("Camera")
{
    GameObject* cameraObject = new GameObject("camera");
    cameraObject->addComponent(this);
    this->gameObject->transform->forward = glm::normalize(forward);
    this->gameObject->transform->up = glm::normalize(up);
    this->gameObject->transform->right = glm::normalize(glm::cross(this->gameObject->transform->up, this->gameObject->transform->forward));
    this->gameObject->tag = MainCamera;
    this->fov = fov;
    this->aspect = aspect;
    this->near = near;
    this->far = far;
    this->orthographic = false;
    this->backgroundColor = Color(0.2f, 0.3f, 0.3f, 1.0f);
    this->clearFlags = Skybox;
    this->cullingMask = layerDefault;
    this->depth = 0;

    allCameras->push_back(this);
}


Camera* hxe::Camera::current = nullptr;

std::vector<Camera*>* hxe::Camera::allCameras = new std::vector<Camera *>();


void hxe::Camera::sortCamera()
{
    sort(Camera::allCameras->begin(), Camera::allCameras->end(), Camera::sortFun);
}


Camera* hxe::Camera::getMainCamera()
{
    if (main == nullptr)
    {
        for (unsigned int i = 0; i < Camera::allCameras->size(); i++)
        {
            Camera* camera = (*Camera::allCameras)[i];
            if (camera->gameObject->tag == MainCamera)
            {
                main = camera;
                break;
            }
        }
    }

    return main;
}

bool hxe::Camera::sortFun(const Camera* a, const Camera* b)
{
    return a->depth < b->depth;
}


Camera* hxe::Camera::main = nullptr;

hxe::Camera::Camera(float orthographicSize, float aspect, float near, float far) : Component("Camera")
{
    GameObject* cameraObject = new GameObject("orthographicCamera");
    cameraObject->addComponent(this);
    this->orthographicSize = orthographicSize;
    this->aspect = aspect;
    this->near = near;
    this->far = far;
    this->orthographic = true;
    this->backgroundColor = Color(0.2f, 0.3f, 0.3f, 1.0f);
    this->clearFlags = Depth;
    this->cullingMask = layerUI;
    this->depth = 0;

    allCameras->push_back(this);
}

Matrix4x4 hxe::Camera::getViewMatrix() const
{
    Vector3 position = gameObject->transform->position;
    return glm::lookAt(position, position - this->gameObject->transform->forward, this->gameObject->transform->up);
}

Matrix4x4 hxe::Camera::getProjectionMatrix() const
{
    if (orthographic)
    {
        float halfHeight = orthographicSize;
        float halfWidth = orthographicSize * aspect;
        return glm::ortho(-halfWidth, halfWidth, -halfHeight, halfHeight, this->near, this->far);
    }
    else 
    {
        return glm::perspective(this->fov, this->aspect, this->near, this->far);
    }
}


void hxe::Camera::begin()
{
    if (clearFlags == SolidColor || clearFlags == Skybox) {
        glClearColor(backgroundColor.r, backgroundColor.g, backgroundColor.b, backgroundColor.a);
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    }
    else if (clearFlags == Depth) {
        glClear(GL_DEPTH_BUFFER_BIT);
    }
    
    if(clearFlags == Skybox && SkyBox::skybox != nullptr) {
        SkyBox::skybox->draw();
    }

}

Matrix4x4 Camera::getViewProjectionMatrix() const
{
    Matrix4x4 view = getViewMatrix();
    Matrix4x4 proj = getProjectionMatrix();
    return proj * view;
}


void Camera::update()
{
}
